﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Gear : Unit, IAngularVelocityDeliever, ILinearVelocityDeliever
{
    public float Radius = 1;
    public float ToothStartAngle = 0;
    public float ToothEndAngle = Mathf.PI * 2;
    public bool Convex = false;
    public bool ClockwiseThooth = true;
    public bool CounterClockwiseThooth = true;

    public float AngularDelta { get; private set; }

    protected override void Sync()
    {
        base.Sync();
        BeginSync();
        SyncFloat(ref Radius);
        SyncFloat(ref ToothStartAngle);
        SyncFloat(ref ToothEndAngle);
        SyncBool(ref Convex);
        SyncBool(ref ClockwiseThooth);
        SyncBool(ref CounterClockwiseThooth);
        EndSync();
    }

    public float LinearDelta(float angle)
    {
        var a = MathEx.RangeInPi2(angle - Angle + AngularDelta / 2);
        if (a < ToothStartAngle || a > ToothEndAngle)
            return 0;
        else if (AngularDelta > 0 && !CounterClockwiseThooth) // 逆时针不传动
            return 0;
        else if (AngularDelta < 0 && !ClockwiseThooth) // 顺时针不传动
            return 0;

        return AngularDelta * Mathf.PI * 2 * GetRadius(a);
    }

    public override Vector2 PositionOffset(float angle)
    {
        var r = GetRadius(angle - Angle);
        return new Vector2(Mathf.Cos(angle) * r, Mathf.Sin(angle) * r);
    }

    public float GetRadius(float angle)
    {
        var r = Radius;
        if (Convex)
        {
            // 是凸轮
            angle = MathEx.RangeInPi2(angle);
            if (angle <= Mathf.PI)
            {
                var a = angle / 2;
                var d = Mathf.Cos(a) * Mathf.Sin(a);
                return r * (1 + Mathf.Pow(d, 4) * Mathf.Pow(2, 2));
            }
            else
                return r;
        }
        else
            return r;
    }

    public override void UpdateSelf(float te, ConnectionType dt)
    {
        if (Src == null)
            return;

        var d = (Pos - Src.Pos);
        var arcFromSrc = MathEx.Arc(d.x, d.y);
        var arcToSrc = MathEx.Arc(-d.x, -d.y);

        if (dt == ConnectionType.Concentric)
        {
            AngularDelta = (Src as IAngularVelocityDeliever).AngularDelta;
            Angle += AngularDelta;
            Pos = Src.Pos;
        }
        else if (dt == ConnectionType.Clenching)
        {
            var linearDelta = 0f;
            var a = MathEx.RangeInPi2(arcToSrc - Angle);
            if (a >= ToothStartAngle && a <= ToothEndAngle)
                linearDelta = -(Src as ILinearVelocityDeliever).LinearDelta(arcFromSrc);

            // 从动传动方向和主动刚好是相反的
            if (linearDelta > 0 && !ClockwiseThooth)
                linearDelta = 0;
            else if (linearDelta < 0 && !CounterClockwiseThooth)
                linearDelta = 0;

            AngularDelta = linearDelta / Mathf.PI / GetRadius(arcToSrc - Angle) / 2;
            Angle += AngularDelta;
            Pos = Src.Pos + Src.PositionOffset(arcFromSrc) - PositionOffset(arcToSrc);
        }
    }
}
